package net.hzlj.platform.enterprise.socket.mina;

import android.text.TextUtils;
import android.util.Log;

import net.hzlj.platform.enterprise.BootApp;
import net.hzlj.platform.enterprise.common.Constant;
import net.hzlj.platform.enterprise.config.HttpConfig;
import net.hzlj.platform.enterprise.socket.SocketService;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

/**
 * http://chwshuang.iteye.com/blog/2028951
 * @Description:
 * @Author: Jason Zhang
 * @Date: 2016/12/6 0006
 */

public class MinaClientManager implements SocketService {

    private static final String TAG = MinaClientManager.class.getSimpleName();

    private static final MinaClientManager instance = new MinaClientManager();

    private IoSession mSession;
    private IoConnector mIoConnector;

    public static MinaClientManager getInstance() {
        return instance;
    }

    private MinaClientManager() {

    }

    private Subscription mReconnectSubscription;

    //重新链接
    @Override
    public synchronized void reconnect(){
        mReconnectSubscription = Observable.create(new Observable.OnSubscribe<String>() {

            @Override
            public void call(Subscriber<? super String> subscriber) {
                if (mIoConnector == null){
                    mIoConnector = new NioSocketConnector();
                    //设置链接超时时间
                    mIoConnector.setConnectTimeoutMillis(Constant.Socket.CONNECTION_TIMEOUT_TIME);
                    //添加过滤器
                    if (mIoConnector.getFilterChain().get("logger") == null){
                        mIoConnector.getFilterChain().addLast("logger", new LoggingFilter());
                    }
                    if (mIoConnector.getFilterChain().get("codec") == null){
                        Log.i(TAG,"encodingDelimiter:" + LineDelimiter.WINDOWS.getValue());
//                        mIoConnector.getFilterChain().addLast("codec",
//                                new ProtocolCodecFilter(
//                                        new TextLineCodecFactory(Charset.forName("UTF-8"),
//                                                LineDelimiter.WINDOWS.getValue(), "\r\n")));
                        mIoConnector.getFilterChain().addLast("codec",
                                new ProtocolCodecFilter(
                                        new TextLineCodecFactory(Charset.forName("UTF-8"),"]","]")));
                    }
                    mIoConnector.getSessionConfig().setReadBufferSize(1024);
                    mIoConnector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60000);//读写都空闲时间:1秒
                    mIoConnector.setHandler(new MinaClientHandler());
                    mIoConnector.setDefaultRemoteAddress(new InetSocketAddress(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT));
                    mIoConnector.addListener(mIoServiceListener);
                    //开始连接
                    try {
                        ConnectFuture future = mIoConnector.connect(new InetSocketAddress(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT));
                        future.awaitUninterruptibly();// 等待连接创建完成
                        mSession = future.getSession();// 获得session
                        //判断是否连接服务器成功
                        if (mSession != null && mSession.isConnected()) {
                            Log.i(TAG,"初始化网络链接状况：成功");
                            mSession.write(Constant.Socket.HEART_BEAT_MESSAGE + BootApp.getInstance().getUserId());
                        } else {
                            Log.i(TAG,"初始化网络链接状况：失败");
                        }
                        System.out.println(11);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.i(TAG,"客户端链接异常...");
                    }
                    if (mSession != null && mSession.isConnected()) {
                        mSession.getCloseFuture().awaitUninterruptibly();// 等待连接断开
                        Log.i(TAG,"客户端断开");
                        // connector.dispose();//彻底释放Session,退出程序时调用不需要重连的可以调用这句话，也就是短连接不需要重连。长连接不要调用这句话，注释掉就OK。
                    }
                }
                if (!isConnection()){
                    ConnectFuture future = mIoConnector.connect(new InetSocketAddress(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT));
                    future.awaitUninterruptibly();// 等待连接创建完成
                    mSession = future.getSession();
                    if (mSession != null && mSession.isConnected()){
                        subscriber.onCompleted();
                    }else {
                        subscriber.onError(new Throwable("Connection Failed"));
                    }
                }
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(mCallBackObserver);
    }


    private Observer mCallBackObserver = new Observer<String>() {
        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onNext(String message) {
            mSession.write(message);
        }
    };

    /***
     * 发送消息
     * @param message
     * @return
     */
    @Override
    public void sendMessage(final String message){
        try{
            Observable.create(new Observable.OnSubscribe<String>() {
                @Override
                public void call(Subscriber<? super String> subscriber) {
                    subscriber.onNext(message);
                    subscriber.onCompleted();
                }
            }).filter(new Func1<String, Boolean>() {
                @Override
                public Boolean call(String s) {
                    return !TextUtils.isEmpty(s) && isConnection() && BootApp.getInstance().getUserId() !=0;
                }
            }).subscribe(mCallBackObserver);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //主动关闭链接
    @Override
    public void close(){
        if (mSession != null && mSession.isConnected()){
            mSession.close(true);
        }
    }

    /**
     * 检查Socket是否连接
     * @return
     */
    @Override
    public boolean isConnection(){
        boolean flag = mIoConnector != null && mSession != null && mSession.isConnected();
        Log.i(TAG,flag ? "监测连接状况：成功" : "监测连接状况：失败");
        return flag;
    }

    private MinaServiceListener mIoServiceListener = new MinaServiceListener() {

        @Override
        public void sessionDestroyed(IoSession session) throws Exception {
        }
    };

}
